/*
 * @file     g_sysctrl.c
 * @brief    This file contains all the functions prototypes for the sysctrl firmware library.
 *
 * Change Logs:
 * Date            Author             Version        Notes
 * 2021-05-19      dengzhiqian        V1.0.0         the first version
 * 2021-05-19      dengzhiqian        V1.0.1         modify the DPLL coefficient configuration
 * 2022-07-11      dengzhiqian        V1.0.2         add lightsleep paradef
 * 2022-07-21      dengzhiqian        V1.0.3         add exen config and iofp config in poweroff api
 * 2023-02-09      dengzhiqian        V1.0.4         add HvldoOcpSel api and read otp dvdd lpm data in lightsleep
 * 2023-07-20      lihaotian          V1.0.5         avoid wake up failures due to G_prefetch
 */

/* Includes ------------------------------------------------------------------*/
#include "g_sysctrl.h"


#define USER_IO_CFG_SADDR   (128-1)
#define USER_IO_CFG_LEN     (10)
#define USER_IO_FUN_SADDR   (USER_IO_CFG_SADDR-USER_IO_CFG_LEN)

/* Exported functions -------------------------------------------------------*/
/**
 * @method G_SYSCTRL_AHBPeriphClockCmd
 * @brief  Enables or disables the AHB peripheral clock.
 * @param  G_SYSCTRL_AHBPeriph: specifies the AHB peripheral to gates its clock.
 *   For @b this parameter can be any combination
 *   of the following values:
 *     @arg SYSCTRL_AHBPeriph_RNG
 *     @arg SYSCTRL_AHBPeriph_QSPI
 *     @arg SYSCTRL_AHBPeriph_SHA
 *     @arg SYSCTRL_AHBPeriph_CRC
 *     @arg SYSCTRL_AHBPeriph_USB
 *     @arg SYSCTRL_AHBPeriph_SPI
 *     @arg SYSCTRL_AHBPeriph_DES
 *     @arg SYSCTRL_AHBPeriph_RSACTRL
 *     @arg SYSCTRL_AHBPeriph_AES
 *     @arg SYSCTRL_AHBPeriph_GPIO
 *     @arg SYSCTRL_AHBPeriph_SM4
 *     @arg SYSCTRL_AHBPeriph_UART
 *     @arg SYSCTRL_AHBPeriph_7811
 *     @arg SYSCTRL_AHBPeriph_7811_ADC
 *     @arg SYSCTRL_AHBPeriph_CP
 *     @arg SYSCTRL_AHBPeriph_PSRAM
 *     @arg SYSCTRL_AHBPeriph_HSPI
 *     @arg SYSCTRL_AHBPeriph_DAC
 *     @arg SYSCTRL_AHBPeriph_DCMI
 *     @arg SYSCTRL_AHBPeriph_SDIO
 *     @arg SYSCTRL_AHBPeriph_CP192M
 * @param  NewState: new state of the specified peripheral clock.
 *   This parameter can be: ENABLE or DISABLE.
 *   Peripheral enabled by default: SYSCTRL_AHBPeriph_SHA/SYSCTRL_AHBPeriph_SPI/SYSCTRL_AHBPeriph_GPIO
 * @retval None
 */
void G_SYSCTRL_AHBPeriphClockCmd(uint32_t G_SYSCTRL_AHBPeriph, G_FunctionalState NewState)
{
    _ASSERT(IS_SYSCTRL_AHB_PERIPH(G_SYSCTRL_AHBPeriph));

    if (DISABLE == NewState)
    {
        MRCC->CLK_EN.reg |= G_SYSCTRL_AHBPeriph;
    }
    else
    {
        MRCC->CLK_EN.reg &= ~G_SYSCTRL_AHBPeriph;
    }
}
void SYSCTRL_AHBPeriphClockCmd(uint32_t G_SYSCTRL_AHBPeriph, 
				G_FunctionalState NewState)
{
	G_SYSCTRL_AHBPeriphClockCmd(G_SYSCTRL_AHBPeriph, NewState);
}

/**
 * @method G_SYSCTRL_APBPeriphClockCmd
 * @brief  Enables or disables the APB peripheral clock.
 * @param  G_SYSCTRL_APBPeriph: specifies the APB peripheral to gates its clock.
 *   For @b this parameter can be any combination
 *   of the following values:
 *     @arg SYSCTRL_APBPeriph_PWM
 *     @arg SYSCTRL_APBPeriph_WDT
 *     @arg SYSCTRL_APBPeriph_7816CTRL
 *     @arg SYSCTRL_APBPeriph_7816CTRL_2
 * @param  NewState: new state of the specified peripheral clock.
 *   This parameter can be: ENABLE or DISABLE.
 *   Peripheral enabled by default:SYSCTRL_APBPeriph_PWM/SYSCTRL_APBPeriph_WDT
 * @retval None
 */
void G_SYSCTRL_APBPeriphClockCmd(uint32_t G_SYSCTRL_APBPeriph, G_FunctionalState NewState)
{
    _ASSERT(IS_SYSCTRL_APB_PERIPH(G_SYSCTRL_APBPeriph));

    if (DISABLE == NewState)
    {
        MRCC->CLK_EN.reg |= G_SYSCTRL_APBPeriph;
    }
    else
    {
        MRCC->CLK_EN.reg &= ~G_SYSCTRL_APBPeriph;
    }
}

/**
 * @method G_SYSCTRL_RVPeriphClockCmd
 * @brief  Enables or disables the RV peripheral clock.
 * @param  G_SYSCTRL_RVPeriph: specifies the RV peripheral to gates its clock.
 *   For @b this parameter can be any combination
 *   of the following values:
 *     @arg SYSCTRL_RVPeriph_MEMCP
 *     @arg SYSCTRL_RVPeriph_MPU_DMA
 *     @arg SYSCTRL_RVPeriph_RV_SYS
 *     @arg SYSCTRL_RVPeriph_RV_REG
 * @param  NewState: new state of the specified peripheral clock.
 *   This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void G_SYSCTRL_RVPeriphClockCmd(uint32_t G_SYSCTRL_RVPeriph, G_FunctionalState NewState)
{
    _ASSERT(IS_SYSCTRL_RV_PERIPH(G_SYSCTRL_RVPeriph));

    if (DISABLE == NewState)
    {
        MRCC->CLK_EN.reg |= G_SYSCTRL_RVPeriph;
    }
    else
    {
        MRCC->CLK_EN.reg &= ~G_SYSCTRL_RVPeriph;
    }
}

/**
 * @method G_SYSCTRL_RC48MPeriphClockCmd
 * @brief  Enables or disables the RV peripheral clock.
 * @param  NewState: new state of the specified peripheral clock.
 *   This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void G_SYSCTRL_RC48MPeriphClockCmd(G_FunctionalState NewState)
{
    if (DISABLE == NewState)
    {
        MRCC->CLK_EN.reg |= SYSCTRL_RC48MMPeriph;
    }
    else
    {
        MRCC->CLK_EN.reg &= ~SYSCTRL_RC48MMPeriph;
    }
}

/**
 * @method G_SYSCTRL_HCLKPeriphSelect
 * @brief  HCLK peripheral clock selection USB&UART.
 * @param  Periph: specifies the HCLK peripheral to gates its clock.
 *   For @b this parameter can be any combination
 *   of the following values:
 *     @arg SYSCTRL_AHBPeriph_UART
 *     @arg SYSCTRL_AHBPeriph_USB
 * @param  Select: new source of the specified peripheral clock.
 *   This parameter can be: RC192_48M, HSI48M or HSE48M.
 * @retval None
 */
void G_SYSCTRL_HCLKPeriphSelect(uint32_t Periph, G_HCLK_Select Select)
{
    _ASSERT(IS_SYSCTRL_AHB_PERIPH(Periph));
    _ASSERT(IS_SYSCTRL_HCLK_SELECT(Select));

    if (SYSCTRL_AHBPeriph_UART == Periph)
    {
        MRCC->HCLK_CTRL.bit.UART_SEL = Select;
    }
    else if (SYSCTRL_AHBPeriph_USB == Periph)
    {
        MRCC->HCLK_CTRL.bit.USB_SEL = Select;
    }
}

/**
 * @method G_SYSCTRL_MCUClkRandCmd
 * @brief  HCLK random number mask enabled.
 * @param  NewState: new state of the specified peripheral clock.
 *   This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void G_SYSCTRL_MCUClkRandCmd(G_FunctionalState NewState)
{
    MRCC->MCU_CLK.bit.RAND_EN = NewState;
}

/**
 * @method G_SYSCTRL_MCUClkRandMask
 * @brief  HCLK random number mask coefficient.
 * @param  randmask: 0x0~0xf
 * @retval None
 */
void G_SYSCTRL_MCUClkRandMask(uint8_t randmask)
{
    _ASSERT(IS_SYSCTRL_MCU_RANDMASK(randmask));

    MRCC->MCU_CLK.bit.RAND_MASK = randmask;
}

/**
 * @method G_SYSCTRL_PLLFreqConfig
 * @brief  pll output frequency config
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  PLLChanel:
 * @retval None
 */
void G_SYSCTRL_PLLFreqConfig(uint8_t PllSource, uint8_t PllFreq)
{
    if (PllSource == PLL_HSE)
    {
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_RSTN = RESET;

        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_RSTN = SET;
    }
    else
    {
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_RSTN = RESET;

        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_RSTN = SET;
    }
}

/**
 * @method G_SYSCTRL_PLLCrystalConfig
 * @brief  pll input frequency config
 * @param  OscFreq: input osc clk freq
 * @retval None
 */
void G_SYSCTRL_PLLCrystalConfig(G_SYSCTRL_PLLCrystal_TypeDef Mode, uint32_t OscFreq)
{
    uint8_t BBpllDivrInt = 0;
    uint32_t BBpllDivrFrac = 0;
    uint32_t BBpllFreq = CLOCK_FRE_384M;
    /*open xtal*/
    G_BPU_Init();
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN = SET;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = SET;

    if (Mode == XTAL_MODE)
    {
        MLPM->OSC_XTAL.bit.OSC_XTAL_REF_MODE_EN = RESET;
    }
    else
    {
        MLPM->OSC_XTAL.bit.OSC_XTAL_REF_MODE_EN = SET;
    }

    BBpllDivrInt = BBpllFreq / OscFreq;
    OscFreq /= CLOCK_FRE_BASE;
    BBpllDivrFrac = BBpllFreq / OscFreq;
    BBpllDivrFrac %= CLOCK_FRE_BASE;
    BBpllDivrFrac /= 10000;
    ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_DIVR_INT = BBpllDivrInt;
    // ANA_BBPLL->BBPLL1_CTRL1.bit.BBPLL1_DIVR_FRAC = BBpllDivrFrac;
    ANA_BBPLL->BBPLL1_CTRL1.bit.BBPLL1_DIVR_FRAC = BBpllDivrFrac * (1 << 24) / 100;
    delay_us(5);
}

/**
 * @method G_SYSCTRL_PLLConfig
 * @brief  pll output frequency config
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  PLLChanel:
 *     @arg  pll channel input selection for G_SYSCTRL_PLLChannel_TypeDef.
 * @retval None
 */
void G_SYSCTRL_PLLOpen(uint8_t PllSource, uint8_t PLLChannel)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));

    /*default config dpll1 hse input dpll2 hsi rc input*/
    ANA_BBPLL->BBPLL_CTRL.bit.BBPLL_CKIN_SEL = RESET;

    /*Bpll Ldo enable*/
    ANA_LDO_CLK->LDO_CTRL.bit.LDO_HVSEL = RESET;
    ANA_LDO_CLK->LDO_CTRL.bit.LDO_IBLOAD_SEL = SET;

    if (PllSource == PLL_HSE)
    {
        /*open xtal*/
        G_BPU_Init();
        MLPM->OSC_XTAL.bit.OSC_XTAL_EN = SET;
        MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = SET;

        ANA_LDO_CLK->LDO_CTRL.bit.LDO_EN_BBPLL1 = SET;
        delay_us(5);

        /*dpll1 block en */
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN = SET;
        if (PLLChannel & PLL_CHANNEL_48MHz)
        {
            ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_48M = SET;
        }
        if (PLLChannel & PLL_CHANNEL_192MHz)
        {
            ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_192M = SET;
        }
        if (PLLChannel & PLL_CHANNEL_256MHz)
        {
            ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_256M = SET;
        }
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_CK48M_DIV2 = RESET;
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_LOOPDIV = SET;
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_PFDCP = SET;
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_VCO = SET;
    }
    else
    {
        ANA_LDO_CLK->LDO_CTRL.bit.LDO_EN_BBPLL2 = SET;
        delay_us(5);
        /*dpll2 block en*/
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN = SET;
        if (PLLChannel & PLL_CHANNEL_48MHz)
        {
            ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_48M = SET;
        }
        if (PLLChannel & PLL_CHANNEL_192MHz)
        {
            ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_192M = SET;
        }
        if (PLLChannel & PLL_CHANNEL_256MHz)
        {
            ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_256M = SET;
        }
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_CK48M_DIV2 = RESET;
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_LOOPDIV = SET;
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_PFDCP = SET;
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_VCO = SET;
    }

    delay_us(5);
    ANA_LDO_CLK->LDO_CTRL.bit.LDO_IBLOAD_SEL = RESET;

    ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_RSTN = SET;
    ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_RSTN = SET;
}

/**
 * @method G_SYSCTRL_PLLConfig
 * @brief  pll output frequency config
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  PLLChanel:
 *     @arg  pll channel input selection for G_SYSCTRL_PLLChannel_TypeDef.
 * @retval None
 */
void G_SYSCTRL_PLLClose(uint8_t PllSource, uint8_t PLLChannel)
{
    if (PllSource == PLL_HSE)
    {
        if (PLLChannel & PLL_CHANNEL_48MHz)
        {
            ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_48M = RESET;
        }
        if (PLLChannel & PLL_CHANNEL_192MHz)
        {
            ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_192M = RESET;
        }
        if (PLLChannel & PLL_CHANNEL_256MHz)
        {
            ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_256M = RESET;
        }
    }
    else
    {
        if (PLLChannel & PLL_CHANNEL_48MHz)
        {
            ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_48M = RESET;
        }
        if (PLLChannel & PLL_CHANNEL_192MHz)
        {
            ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_192M = RESET;
        }
        if (PLLChannel & PLL_CHANNEL_256MHz)
        {
            ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_256M = RESET;
        }
    }
}

/**
 * @method G_SYSCTRL_PLLConfig
 * @brief  pll output frequency config
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @retval None
 */
void G_SYSCTRL_PLLDeInit(uint8_t PllSource)
{
    if (PllSource == PLL_HSE)
    {
        /*dpll1 block disable */
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_48M = RESET;
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_192M = RESET;
        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_EN_CLKGEN_256M = RESET;

        ANA_BBPLL->BBPLL1_CTRL2.bit.BBPLL1_RSTN = RESET;

        /*dpll1 ldo colse */
        ANA_LDO_CLK->LDO_CTRL.bit.LDO_EN_BBPLL1 = RESET;
        delay_us(5);
        /*close xtal*/
        MLPM->OSC_XTAL.bit.OSC_XTAL_EN = RESET;
        MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = RESET;
    }
    else
    {
        /*dpll1 block disable */
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_48M = RESET;
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_192M = RESET;
        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_EN_CLKGEN_256M = RESET;

        ANA_BBPLL->BBPLL2_CTRL2.bit.BBPLL2_RSTN = RESET;

        /*dpll1 ldo colse */
        ANA_LDO_CLK->LDO_CTRL.bit.LDO_EN_BBPLL2 = RESET;
        delay_us(5);
    }
}

/**
 * @method G_SYSCTRL_GetPllFreq
 * @brief  get pll frequency
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @retval pll frequency
 */
static uint32_t G_SYSCTRL_GetPllFreq(uint8_t PllSource, uint8_t PLLChannel)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));

    uint32_t Pll_Freq = 0;

    if (PllSource == PLL_HSE)
    {
        /*HSE Pll freq getting*/
        if (PLLChannel == PLL_CHANNEL_192MHz)
        {
            return CLOCK_FRE_192M;
        }
        if (PLLChannel == PLL_CHANNEL_256MHz)
        {
            return CLOCK_FRE_256M;
        }
    }
    else
    {
        /*HSI Pll freq getting*/
        if (PLLChannel == PLL_CHANNEL_192MHz)
        {
            return CLOCK_FRE_192M;
        }
        if (PLLChannel == PLL_CHANNEL_256MHz)
        {
            return CLOCK_FRE_256M;
        }
    }

    return Pll_Freq;
}
/**
 * @method G_SYSCTRL_MCUClkPllSelect
 * @brief  Master clock PLL input source selection.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @retval None
 */
static void G_SYSCTRL_MCUClkPllSelect(uint8_t PllSource)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));

    MRCC->CLK_PLL_SEL.bit.MCU_PLL_SEL = PllSource;
}

/**
 * @method G_SYSCTRL_MCUClkSourceSelect
 * @brief  Input source selection for master clock source.
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg MCU_RC32K
 *     @arg MCU_RC192M
 *     @arg MCU_PLL_OUT_NORM
 *     @arg MCU_PLL_OUT_MAX
 *     @arg MCU_PLL_OUT_FIXED
 * @retval None
 */
static void G_SYSCTRL_MCUClkSourceSelect(G_SYSCLK_MCUSource_TypeDef Source)
{
    _ASSERT(IS_SYSCTRL_MCUSOURCE_SEL(Source));

    /*enable rc32k as cpu clk */
    if (Source == MCU_RC32K)
    {
        MRCC->MCU_CLK.bit.RC_32K = SET;
    }

    MRCC->MCU_CLK.bit.SEL = Source;
}

/**
 * @method G_SYSCTRL_MCUClkDiv
 * @brief  Selection of frequency division coefficient of master clock.
 * @param  Clk_Div: SYSCTRL_CLK_Div_None...SYSCTRL_CLK_Div32.
 * @retval None
 */
static void G_SYSCTRL_MCUClkDiv(uint32_t Clk_Div)
{
    _ASSERT(IS_SYSCTRL_CLK_DIV(Clk_Div));

    MRCC->MCU_CLK.bit.DIV_EN = SET;

    if (SYSCTRL_CLK_Div_None == Clk_Div)
    {
        MRCC->MCU_CLK.bit.DIV_SEL = RESET;
    }
    else
    {
        MRCC->MCU_CLK.bit.DIV_SEL = SET;
        MRCC->MCU_CLK.bit.DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
        MRCC->MCU_CLK.bit.DIV_LO = Clk_Div >> 1;
    }
}

/**
 * @method G_SYSCTRL_MCUClkCtrl
 * @brief  Master clock source configuration selection.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC_192M
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg MCU_RC192M
 *     @arg MCU_PLL_OUT_NORM(192M)
 *     @arg MCU_PLL_OUT_MAX(256M)
 *     @arg MCU_PLL_OUT_FIXED(48M)
 *     @arg MCU_RC32K
 * @param  Clk_Div: SYSCTRL_CLK_Div_None...SYSCTRL_CLK_Div32.
 * @retval None
 */
void G_SYSCTRL_MCUClkCtrl(uint8_t PllSource, G_SYSCLK_MCUSource_TypeDef Source, uint32_t Clk_Div)
{
    IS_MCU_PLLSOURCE(PllSource, Source);
    /*pll sel*/
    G_SYSCTRL_MCUClkPllSelect(PllSource);

    /*get source freq*/
    uint32_t source_freq;
    G_GET_MCU_SOURCE_FREQ(Source, source_freq);
    source_freq = Clk_Div == SYSCTRL_CLK_Div_None ? source_freq : source_freq / (Clk_Div + 2);

    /*set MCU high active*/
    G_BPU_Init();
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN = SET;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = SET;

    //    if(source_freq > CLOCK_FRE_96M)
    //    {
    //        /*set 1.4v*/
    //        MLPM->LDO_POR.bit.RG_LPM_LDO_SEC_VTRIM = 0xf;
    //    }
    //    else
    //    {
    //        /*set 1.2v*/
    //        MLPM->LDO_POR.bit.RG_LPM_LDO_SEC_VTRIM = 0xd;
    //    }
    //    delay_ms(10);

    /*pll freq config*/
    if (PllSource == PLL_HSI || PllSource == PLL_HSE)
    {
        uint8_t PLLChannel = 0;
        IS_MCU_PLLCHANNEL(Source, PLLChannel);
        G_SYSCTRL_PLLOpen(PllSource, PLLChannel);
    }

    /*source select*/
    G_SYSCTRL_MCUClkSourceSelect(Source);

    /*set clk div*/
    G_SYSCTRL_MCUClkDiv(Clk_Div);

    /*set timer api clk(for delay_us\delay_ms)*/
    uint32_t clk = G_SYSCTRL_GetClocksFreq(MCU_FRE);
    MMCU->CURR_CLK.bit.MS_CLK = clk / CLOCk_FRE_1K;
    MMCU->CURR_CLK.bit.US_CLK = clk / CLOCk_FRE_1M;
}

/**
 * @method G_SYSCTRL_PER1AhbClkCtrl
 * @brief  Peripheral clock 1 AHB bus clock configuration.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC_192M
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PER1_CLKMCU
 *     @arg PER1_RC192M
 *     @arg PER1_PLL_OUT_NORM
 *     @arg PER1_PLL_OUT_FIXED
 * @param  Clk_Div: SYSCTRL_PER1_Div2...SYSCTRL_PER1_Div32.
 * @retval None
 */
void G_SYSCTRL_PER1AhbClkCtrl(uint8_t PllSource, G_SYSCLK_PER1Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));
    _ASSERT(IS_SYSCTRL_PER1SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_PER1_DIV(Clk_Div));
    IS_PER1_PLLSOURCE(PllSource, Source);

    /*pll source config*/
    MRCC->CLK_PLL_SEL.bit.AHB_PLL_SEL = PllSource;

    /*pll freq config*/
    if (PllSource == PLL_HSI || PllSource == PLL_HSE)
    {
        uint8_t PLLChannel = IS_PER1_PLLCHANNEL(Source);
        G_SYSCTRL_PLLOpen(PllSource, PLLChannel);
    }

    /*source select*/
    MRCC->PER1_CLK.bit.AHB_SEL = Source;

    /*set clk div*/
    if (SYSCTRL_CLK_Div_None == Clk_Div)
    {
        MRCC->PER1_CLK.bit.AHB_DIV_HI = 0;
        MRCC->PER1_CLK.bit.AHB_DIV_LO = 0;
    }
    else
    {
        MRCC->PER1_CLK.bit.AHB_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
        MRCC->PER1_CLK.bit.AHB_DIV_LO = Clk_Div >> 1;
    }
}

/**
 * @method G_SYSCTRL_PER1QspiClkCtrl
 * @brief  Peripheral clock 1 QSPI bus clock configuration.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC_192M
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PER1_CLKMCU
 *     @arg PER1_RC192M
 *     @arg PER1_PLL_OUT_NORM
 *     @arg PER1_PLL_OUT_FIXED
 * @param  Clk_Div: SYSCTRL_PER1_Div2...SYSCTRL_PER1_Div32.
 * @retval None
 */
void G_SYSCTRL_PER1QspiClkCtrl(uint8_t PllSource, G_SYSCLK_PER1Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));
    _ASSERT(IS_SYSCTRL_PER1SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_PER1_DIV(Clk_Div));
    IS_PER1_PLLSOURCE(PllSource, Source);
    /*pll source config*/
    MRCC->CLK_PLL_SEL.bit.QSPI_PLL_SEL = PllSource;

    /*pll freq config*/
    if (PllSource == PLL_HSI || PllSource == PLL_HSE)
    {
        uint8_t PLLChannel = IS_PER1_PLLCHANNEL(Source);
        G_SYSCTRL_PLLOpen(PllSource, PLLChannel);
    }

    /*source select*/
    MRCC->PER1_CLK.bit.QSPI_SEL = Source;

    /*set clk div*/
    if (SYSCTRL_CLK_Div_None == Clk_Div)
    {
        MRCC->PER1_CLK.bit.QSPI_DIV_HI = 0;
        MRCC->PER1_CLK.bit.QSPI_DIV_LO = 0;
    }
    else
    {
        MRCC->PER1_CLK.bit.QSPI_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
        MRCC->PER1_CLK.bit.QSPI_DIV_LO = Clk_Div >> 1;
    }
}

/**
 * @method G_SYSCTRL_PER2PsramClkCtrl
 * @brief  Peripheral clock 2 PSRAM bus clock configuration.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC_192M
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PER2_CLKMCU
 *     @arg PER2_RC192M
 *     @arg PER2_PLL_OUT_NORM
 *     @arg PER2_PLL_OUT_MAX
 * @param  Clk_Div: SYSCTRL_CLK_Div_None...SYSCTRL_CLK_Div32.
 * @retval None
 */
void G_SYSCTRL_PER2PsramClkCtrl(uint8_t PllSource, G_SYSCLK_PER2Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));
    _ASSERT(IS_SYSCTRL_PER2SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_CLK_DIV(Clk_Div));
    IS_PER2_PLLSOURCE(PllSource, Source);
    /*pll source config*/
    MRCC->PER2_CLK.bit.PSRAM_PLL_SEL = PllSource;

    /*pll freq config*/
    if (PllSource == PLL_HSI || PllSource == PLL_HSE)
    {
        uint8_t PLLChannel = IS_PER2_PLLCHANNEL(Source);
        G_SYSCTRL_PLLOpen(PllSource, PLLChannel);
    }

    /*source select*/
    MRCC->PER2_CLK.bit.PSRAM_SEL = Source;

    /*enable div en*/
    MRCC->PER2_CLK.bit.PSRAM_DIV_EN = SET;

    /*set clk div*/
    if (SYSCTRL_CLK_Div_None == Clk_Div)
    {
        MRCC->PER2_CLK.bit.PSRAM_DIV_SEL = RESET;
    }
    else
    {
        MRCC->PER2_CLK.bit.PSRAM_DIV_SEL = SET;
        MRCC->PER2_CLK.bit.PSRAM_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
        MRCC->PER2_CLK.bit.PSRAM_DIV_LO = Clk_Div >> 1;
    }
}

/**
 * @method G_SYSCTRL_PER2HspiClkCtrl
 * @brief  Peripheral clock 2 HSPI bus clock configuration.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC_192M
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PER2_CLKMCU
 *     @arg PER2_RC192M
 *     @arg PER2_PLL_OUT_NORM
 *     @arg PER2_PLL_OUT_MAX
 * @param  Clk_Div: SYSCTRL_CLK_Div_None...SYSCTRL_CLK_Div32.
 * @retval None
 */
void G_SYSCTRL_PER2HspiClkCtrl(uint8_t PllSource, G_SYSCLK_PER2Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));
    _ASSERT(IS_SYSCTRL_PER2SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_CLK_DIV(Clk_Div));
    IS_PER2_PLLSOURCE(PllSource, Source);
    /*pll source config*/
    MRCC->PER2_CLK.bit.HSPI_PLL_SEL = PllSource;

    /*pll freq config*/
    if (PllSource == PLL_HSI || PllSource == PLL_HSE)
    {
        uint8_t PLLChannel = IS_PER2_PLLCHANNEL(Source);
        G_SYSCTRL_PLLOpen(PllSource, PLLChannel);
    }

    /*source select*/
    MRCC->PER2_CLK.bit.HSPI_SEL = Source;

    /*enable div en*/
    MRCC->PER2_CLK.bit.HSPI_DIV_EN = SET;

    /*set clk div*/
    if (SYSCTRL_CLK_Div_None == Clk_Div)
    {
        MRCC->PER2_CLK.bit.HSPI_DIV_SEL = RESET;
    }
    else
    {
        MRCC->PER2_CLK.bit.HSPI_DIV_SEL = SET;
        MRCC->PER2_CLK.bit.HSPI_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
        MRCC->PER2_CLK.bit.HSPI_DIV_LO = Clk_Div >> 1;
    }
}

/**
 * @method G_SYSCTRL_EnableFixed48MConfig
 * @brief  enable fixed 48M clock configuration.
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC48M
 *     @arg PLL_HSI_48M
 *     @arg PLL_HSE_48M
 * @retval None
 */
static void G_SYSCTRL_EnableFixed48MConfig(G_PER3CLK_Source_TypeDef Source)
{
    if (Source == RC48M)
    {
        G_SYSCTRL_RC48MPeriphClockCmd(ENABLE);
    }
    else if (Source == PLL_HSI_48M)
    {
        G_SYSCTRL_PLLOpen(PLL_HSI, PLL_CHANNEL_48MHz);
    }
    else
    {
        G_SYSCTRL_PLLOpen(PLL_HSE, PLL_CHANNEL_48MHz);
    }
}
/**
 * @method G_SYSCTRL_PER3IceClkCtrl
 * @brief  Peripheral clock 3 ICE bus clock configuration.
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC48M
 *     @arg PLL_HSI_48M
 *     @arg PLL_HSE_48M
 * @param  Clk_Div: SYSCTRL_PER3_Div2...SYSCTRL_CLK_Div8.
 * @retval None
 */
void G_SYSCTRL_PER3IceClkCtrl(G_PER3CLK_Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_PER3CTRL_SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_PER3_DIV(Clk_Div));

    /*enable 48M source*/
    G_SYSCTRL_EnableFixed48MConfig(Source);

    /*source select*/
    MRCC->PER3_CLK.bit.ICE_SEL = Source;

    /*enable div en*/
    MRCC->PER3_CLK.bit.ICE_EN = SET;

    /*set clk div*/
    MRCC->PER3_CLK.bit.ICE_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
    MRCC->PER3_CLK.bit.ICE_DIV_LO = Clk_Div >> 1;
}

/**
 * @method G_SYSCTRL_PER3AdacClkCtrl
 * @brief  Peripheral clock 3 ADAC bus clock configuration.
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC48M
 *     @arg PLL_HSI_48M
 *     @arg PLL_HSE_48M
 * @param  Clk_Div: SYSCTRL_PER3_Div2...SYSCTRL_CLK_Div8.
 * @retval None
 */
void G_SYSCTRL_PER3AdacClkCtrl(G_PER3CLK_Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_PER3CTRL_SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_PER3_DIV(Clk_Div));

    /*enable 48M source*/
    G_SYSCTRL_EnableFixed48MConfig(Source);

    /*source select*/
    MRCC->PER3_CLK.bit.ADAC_SEL = Source;

    /*enable div en*/
    MRCC->PER3_CLK.bit.ADAC_EN = SET;

    /*set clk div*/
    MRCC->PER3_CLK.bit.ADAC_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
    MRCC->PER3_CLK.bit.ADAC_DIV_LO = Clk_Div >> 1;
}

/**
 * @method G_SYSCTRL_PER3Gpio0ClkCtrl
 * @brief  Peripheral clock 3 GPIO0 bus clock configuration.
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC48M
 *     @arg PLL_HSI_48M
 *     @arg PLL_HSE_48M
 * @param  Clk_Div: SYSCTRL_PER3_Div2...SYSCTRL_CLK_Div8.
 * @retval None
 */
void G_SYSCTRL_PER3Gpio0ClkCtrl(G_PER3CLK_Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_PER3CTRL_SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_PER3_DIV(Clk_Div));

    /*enable 48M source*/
    G_SYSCTRL_EnableFixed48MConfig(Source);

    /*source select*/
    MRCC->PER3_CLK.bit.GPIO0_SEL = Source;

    /*enable div en*/
    MRCC->PER3_CLK.bit.GPIO0_EN = SET;

    /*set clk div*/
    MRCC->PER3_CLK.bit.GPIO0_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
    MRCC->PER3_CLK.bit.GPIO0_DIV_LO = Clk_Div >> 1;
}

/**
 * @method G_SYSCTRL_PER3Gpio1ClkCtrl
 * @brief  Peripheral clock 3 GPIO1 bus clock configuration.
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC48M
 *     @arg PLL_HSI_48M
 *     @arg PLL_HSE_48M
 * @param  Clk_Div: SYSCTRL_PER3_Div2...SYSCTRL_PER3_Div8.
 * @retval None
 */
void G_SYSCTRL_PER3Gpio1ClkCtrl(G_PER3CLK_Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_PER3CTRL_SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_PER3_DIV(Clk_Div));

    /*enable 48M source*/
    G_SYSCTRL_EnableFixed48MConfig(Source);

    /*source select*/
    MRCC->PER3_CLK.bit.GPIO1_SEL = Source;

    /*enable div en*/
    MRCC->PER3_CLK.bit.GPIO1_EN = SET;

    /*set clk div*/
    MRCC->PER3_CLK.bit.GPIO1_DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
    MRCC->PER3_CLK.bit.GPIO1_DIV_LO = Clk_Div >> 1;
}

/**
 * @method G_SYSCTRL_RSAClkRandCmd
 * @brief  RSA random number mask enabled.
 * @param  NewState: new state of the specified peripheral clock.
 *   This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void G_SYSCTRL_RSAClkRandCmd(G_FunctionalState NewState)
{
    MRCC->CLK_RSA.bit.RAND_EN = NewState;
}

/**
 * @method G_SYSCTRL_RSAClkRandMask
 * @brief  RSA random number mask coefficient.
 * @param  randmask: 0x0~0xf
 * @retval None
 */
void G_SYSCTRL_RSAClkRandMask(uint8_t randmask)
{
    _ASSERT(IS_SYSCTRL_RSA_RANDMASK(randmask));

    MRCC->CLK_RSA.bit.RAND_MASK = randmask;
}

/**
 * @method G_SYSCTRL_RSAClkCtrl
 * @brief  rsa clock source configuration selection.
 * @param  PllSource: Internal or external clock source selection.
 * @param  PllSource: Internal or external clock source selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg RC_192M
 *     @arg PLL_HSI
 *     @arg PLL_HSE
 * @param  Source: source input selection.
 * For @b this parameter can be any combination
 *   of the following values:
 *     @arg PER2_CLKMCU
 *     @arg PER2_RC192M
 *     @arg PER2_PLL_OUT_NORM
 *     @arg PER2_PLL_OUT_MAX
 * @param  Clk_Div: SYSCTRL_CLK_Div_None...SYSCTRL_CLK_Div32.
 * @retval None
 */
void G_SYSCTRL_RSAClkCtrl(uint8_t PllSource, G_SYSCLK_PER2Source_TypeDef Source, uint32_t Clk_Div)
{
    _ASSERT(IS_SYSCTRL_PLL_SEL(PllSource));
    _ASSERT(IS_SYSCTRL_PER2SOURCE_SEL(Source));
    _ASSERT(IS_SYSCTRL_CLK_DIV(Clk_Div));
    IS_PER2_PLLSOURCE(PllSource, Source);

    /*pll source config*/
    MRCC->CLK_PLL_SEL.bit.RSA_PLL_SEL = PllSource;

    /*pll freq config*/
    if (PllSource == PLL_HSI || PllSource == PLL_HSE)
    {
        uint8_t PLLChannel = IS_PER2_PLLCHANNEL(Source);
        G_SYSCTRL_PLLOpen(PllSource, PLLChannel);
    }

    /*source select*/
    MRCC->CLK_RSA.bit.SEL = Source;

    /*set clk div*/
    MRCC->CLK_RSA.bit.DIV_HI = (Clk_Div >> 1) + ((Clk_Div & 1) ? 1 : 0);
    MRCC->CLK_RSA.bit.DIV_LO = Clk_Div >> 1;
}

/**
 * @method G_SYSCTRL_GetClocksCorePara
 * @brief  Get clock MCU configuration parameters
 * @param  Clocks_Types: clock exported types,input selection for G_SYSCTRL_Exported_Types
 * @param  ClocksFrePara: output MCU parameters pointer
 * @retval None
 */
static void G_SYSCTRL_GetClocksCorePara(G_SYSCTRL_Exported_Types Clocks_Types, G_SYSCTRL_ClocksFreParaTypeDef *ClocksFrePara)
{
    memset(ClocksFrePara, 0xff, sizeof(G_SYSCTRL_ClocksFreParaTypeDef));
    switch (Clocks_Types)
    {
    case MCU_FRE:
        ClocksFrePara->PllSource = MRCC->CLK_PLL_SEL.bit.MCU_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->MCU_CLK.bit.SEL & 0x03;
        ClocksFrePara->divsel = MRCC->MCU_CLK.bit.DIV_SEL & 0x01;
        ClocksFrePara->div_hi = MRCC->MCU_CLK.bit.DIV_HI & 0xff;
        ClocksFrePara->div_lo = MRCC->MCU_CLK.bit.DIV_LO & 0xff;
        break;
    case PER1_AHB_FRE:
        ClocksFrePara->PllSource = MRCC->CLK_PLL_SEL.bit.AHB_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->PER1_CLK.bit.AHB_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER1_CLK.bit.AHB_DIV_HI & 0x0f;
        ClocksFrePara->div_lo = MRCC->PER1_CLK.bit.AHB_DIV_LO & 0x0f;
        break;
    case PER1_QSPI_FRE:
        ClocksFrePara->PllSource = MRCC->CLK_PLL_SEL.bit.QSPI_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->PER1_CLK.bit.QSPI_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER1_CLK.bit.QSPI_DIV_HI & 0x0f;
        ClocksFrePara->div_lo = MRCC->PER1_CLK.bit.QSPI_DIV_LO & 0x0f;
        break;
    case PER2_HSPI_FRE:
        ClocksFrePara->PllSource = MRCC->PER2_CLK.bit.HSPI_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->PER2_CLK.bit.HSPI_SEL & 0x03;
        ClocksFrePara->divsel = MRCC->PER2_CLK.bit.HSPI_DIV_SEL & 0x01;
        ClocksFrePara->div_hi = MRCC->PER2_CLK.bit.HSPI_DIV_HI & 0x0f;
        ClocksFrePara->div_lo = MRCC->PER2_CLK.bit.HSPI_DIV_LO & 0x0f;
        break;
    case PER2_PSRAM_FRE:
        ClocksFrePara->PllSource = MRCC->PER2_CLK.bit.PSRAM_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->PER2_CLK.bit.PSRAM_SEL & 0x03;
        ClocksFrePara->divsel = MRCC->PER2_CLK.bit.PSRAM_DIV_SEL & 0x01;
        ClocksFrePara->div_hi = MRCC->PER2_CLK.bit.PSRAM_DIV_HI & 0x0f;
        ClocksFrePara->div_lo = MRCC->PER2_CLK.bit.PSRAM_DIV_LO & 0x0f;
        break;
    case PER3_ICE_FRE:
        ClocksFrePara->Source = MRCC->PER3_CLK.bit.ICE_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER3_CLK.bit.ICE_DIV_HI & 0x03;
        ClocksFrePara->div_lo = MRCC->PER3_CLK.bit.ICE_DIV_LO & 0x03;
        break;
    case PER3_ADAC_FRE:
        ClocksFrePara->Source = MRCC->PER3_CLK.bit.ADAC_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER3_CLK.bit.ICE_DIV_HI & 0x03;
        ClocksFrePara->div_lo = MRCC->PER3_CLK.bit.ICE_DIV_LO & 0x03;
        break;
    case PER3_GPIO0_FRE:
        ClocksFrePara->Source = MRCC->PER3_CLK.bit.GPIO0_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER3_CLK.bit.GPIO0_DIV_HI & 0x03;
        ClocksFrePara->div_lo = MRCC->PER3_CLK.bit.GPIO0_DIV_LO & 0x03;
        break;
    case PER3_GPIO1_FRE:
        ClocksFrePara->Source = MRCC->PER3_CLK.bit.GPIO1_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER3_CLK.bit.GPIO1_DIV_HI & 0x03;
        ClocksFrePara->div_lo = MRCC->PER3_CLK.bit.GPIO1_DIV_LO & 0x03;
        break;
    case PCLK_FRE:
        ClocksFrePara->PllSource = MRCC->CLK_PLL_SEL.bit.AHB_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->PER1_CLK.bit.AHB_SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->PER1_CLK.bit.AHB_DIV_HI & 0x0f;
        ClocksFrePara->div_lo = MRCC->PER1_CLK.bit.AHB_DIV_LO & 0x0f;
        break;
    case RSA_FRE:
        ClocksFrePara->PllSource = MRCC->CLK_PLL_SEL.bit.RSA_PLL_SEL & 0x0f;
        ClocksFrePara->Source = MRCC->CLK_RSA.bit.SEL & 0x03;
        ClocksFrePara->div_hi = MRCC->CLK_RSA.bit.DIV_HI & 0x0f;
        ClocksFrePara->div_lo = MRCC->CLK_RSA.bit.DIV_LO & 0x0f;
        break;
    }
}

/**
 * @method G_SYSCTRL_GetMcuClocksSource
 * @brief  Get MCU clock exported source freq
 * @param  Source: clock exported types,input selection for G_SYSCLK_MCUSource_TypeDef
 * @retval MCU freq
 */
static uint32_t G_SYSCTRL_GetMcuClocksSource(G_SYSCTRL_ClocksFreParaTypeDef *Clock_Para)
{
    _ASSERT(IS_SYSCTRL_MCUSOURCE_SEL(Clock_Para->Source));

    uint32_t Clock_Freq;
    switch (Clock_Para->Source)
    {
    case MCU_RC192M:
        Clock_Freq = CLOCK_FRE_192M;
        break;
    case MCU_PLL_OUT_NORM:
        Clock_Freq = G_SYSCTRL_GetPllFreq(Clock_Para->PllSource, PLL_CHANNEL_192MHz);
        break;
    case MCU_PLL_OUT_MAX:
        Clock_Freq = G_SYSCTRL_GetPllFreq(Clock_Para->PllSource, PLL_CHANNEL_256MHz);
        break;
    case MCU_PLL_OUT_FIXED:
        Clock_Freq = CLOCK_FRE_48M;
        break;
    case MCU_RC32K:
        Clock_Freq = CLOCK_FRE_32K;
        break;
		default:
				Clock_Freq = CLOCK_FRE_192M;
				break;
    }
    return Clock_Freq;
}

/**
 * @method G_SYSCTRL_GetMcuClkFreq
 * @brief  Get MCU clock freq
 * @retval MCU freq
 */
static uint32_t G_SYSCTRL_GetMcuClkFreq(void)
{
    uint32_t Mcu_Clk_Freq = CLOCK_FRE_192M;
    G_SYSCTRL_ClocksFreParaTypeDef McuClocksFrePara;

    G_SYSCTRL_GetClocksCorePara(MCU_FRE, &McuClocksFrePara);

    Mcu_Clk_Freq = G_SYSCTRL_GetMcuClocksSource(&McuClocksFrePara);

    if (McuClocksFrePara.divsel == SET)
    {
        Mcu_Clk_Freq /= (McuClocksFrePara.div_hi + McuClocksFrePara.div_lo + 2);
    }
    /*enable rc32k as clk cpu,ignore all other confings*/
    if (MRCC->MCU_CLK.bit.RC_32K == SET)
    {
        Mcu_Clk_Freq = CLOCK_FRE_32K;
    }

    return Mcu_Clk_Freq;
}

/**
 * @method G_SYSCTRL_GetPER1ClocksSource
 * @brief  Get per1 clock exported source freq
 * @retval per1 freq
 */
static uint32_t G_SYSCTRL_GetPER1ClocksSource(G_SYSCTRL_ClocksFreParaTypeDef *Clock_Para)
{
    _ASSERT(IS_SYSCTRL_PER1SOURCE_SEL(Clock_Para->Source));

    uint32_t Clock_Freq = CLOCK_FRE_192M;
    switch (Clock_Para->Source)
    {
    case PER1_CLKMCU:
        Clock_Freq = G_SYSCTRL_GetMcuClkFreq();
        break;
    case PER1_RC192M:
        Clock_Freq = CLOCK_FRE_192M;
        break;
    case PER1_PLL_OUT_NORM:
        Clock_Freq = G_SYSCTRL_GetPllFreq(Clock_Para->PllSource, PLL_CHANNEL_192MHz);
        break;
    case MCU_PLL_OUT_FIXED:
        Clock_Freq = CLOCK_FRE_48M;
        break;
    }
    return Clock_Freq;
}

/**
 * @method G_SYSCTRL_GetPER1ClocksSource
 * @brief  Get per1 clock exported source freq
 * @param  Source: clock exported types,input selection for G_SYSCLK_PER2Source_TypeDef
 * @retval per1 freq
 */
static uint32_t G_SYSCTRL_GetPER2ClocksSource(G_SYSCTRL_ClocksFreParaTypeDef *Clock_Para)
{
    _ASSERT(IS_SYSCTRL_PER2SOURCE_SEL(Clock_Para->Source));

    Clock_Para->PllSource = Clock_Para->PllSource == 1 ? PLL_HSE : PLL_HSI;
    uint32_t Clock_Freq = CLOCK_FRE_192M;
    switch (Clock_Para->Source)
    {
    case PER2_CLKMCU:
        Clock_Freq = G_SYSCTRL_GetMcuClkFreq();
        break;
    case PER2_RC192M:
        Clock_Freq = CLOCK_FRE_192M;
        break;
    case PER2_PLL_OUT_NORM:

        Clock_Freq = G_SYSCTRL_GetPllFreq(Clock_Para->PllSource, PLL_CHANNEL_192MHz);
        break;
    case PER2_PLL_OUT_MAX:
        Clock_Freq = G_SYSCTRL_GetPllFreq(Clock_Para->PllSource, PLL_CHANNEL_256MHz);
        break;
    }
    return Clock_Freq;
}

/**
 * @method G_SYSCTRL_GetClocksFreq
 * @brief  Get clock exported freq
 * @param  Clocks_Types: clock exported types,input selection for G_SYSCTRL_ClocksFreParaTypeDef
 * @retval freq
 */
uint32_t G_SYSCTRL_GetClocksFreq(G_SYSCTRL_Exported_Types Clocks_Types)
{
    _ASSERT(IS_SYSCTRL_EXPORTED_TYPES(Clocks_Types));

    uint32_t Clock_Freq = 0;
    G_SYSCTRL_ClocksFreParaTypeDef ClocksFrePara;

    G_SYSCTRL_GetClocksCorePara(Clocks_Types, &ClocksFrePara);

    /*get source clock*/

    if (Clocks_Types == MCU_FRE)
    {
        /*get MCU clock freq*/
        Clock_Freq = G_SYSCTRL_GetMcuClkFreq();

        return Clock_Freq;
    }

    /*get fer1 source clock freq*/
    else if (Clocks_Types == PER1_AHB_FRE || Clocks_Types == PER1_QSPI_FRE || Clocks_Types == PCLK_FRE)
    {
        Clock_Freq = G_SYSCTRL_GetPER1ClocksSource(&ClocksFrePara);
    }

    /*get fer2 and rsa source clock freq*/
    else if (Clocks_Types == PER2_HSPI_FRE || Clocks_Types == PER2_PSRAM_FRE || Clocks_Types == RSA_FRE)
    {
        Clock_Freq = G_SYSCTRL_GetPER2ClocksSource(&ClocksFrePara);
    }
    else
    {
        /*per3 source clock*/
        Clock_Freq = CLOCK_FRE_48M;
    }

    /*freq div after clock,(only MCU have divsel)*/

    if (ClocksFrePara.divsel != RESET)
    {
        Clock_Freq /= (uint32_t)(ClocksFrePara.div_hi + ClocksFrePara.div_lo + 2);
    }

    /*pclk : freq div after ahb clock*/

    if (Clocks_Types == PCLK_FRE && MRCC->PCLK_CTRL.bit.DIV_EN == SET)
    {
        Clock_Freq /= (uint32_t)(MRCC->PCLK_CTRL.bit.SEL + 1);
    }

    return Clock_Freq;
}

/**
 * @method G_SYSCTRL_DeepSleep_flashPowerDown
 * @brief  flash Power Down and cpu enter DeepSleep mode
 * @param  None
 * @retval None
 */
#ifdef __ICCARM__
/*将函数放入独立section,防止编译优化导致函数体与用到的常量分离*/
#pragma location = "PREFETCH_G_SYSCTRL_DeepSleep_flashPowerDown"
#endif
void G_SYSCTRL_DeepSleep_flashPowerDown(void)
{
    ((void (*)(uint8_t cmd))(FUNC_QSPI_FLASH_CMD))(0xB9); // flash power down
    for (int i = 0; i < 80; i++)
    {
        if (GPIO_CONFIG(i) >= QSPI_NCS && GPIO_CONFIG(i) <= QSPI_IO3)
        {
            GPIO_CONFIG(i) = PULL_PU;
        }
        else if (GPIO_CONFIG(i) == (ICE | PULL_PU) || GPIO_CONFIG(i) == JTAG_SWCLK || GPIO_CONFIG(i) == JTAG_SWDIO)
        {
            GPIO_CONFIG(i) = ANALOG;
        }
    }

    MLPM->GPIO_LATCH.bit.LATCH = ENABLE;
    MLPM->DEEP_SLEEP.reg = 0x5a;
    ((void (*)(int))(FUNC_DELAY_MS_ADDR))(100);
}

/**
 * @method G_SYSCTRL_DeepSleep
 * @brief  cpu enter standby mode
 * @param  None
 * @retval None
 */

void G_SYSCTRL_DeepSleep(void)
{
    G_LPM_AccessCode(ENABLE);
    G_LPM_RegisterClk(ENABLE);
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN = RESET;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = RESET;
    //	MLPM->PWK_CTRL.bit.LDO_OFF = ENABLE;//使用内部LDO时需要屏蔽
    uint32_t flashPowerDown_addr = (uint32_t)G_SYSCTRL_DeepSleep_flashPowerDown;
    ((void (*)(void *, void *))FUNC_PREFETCH)(((void *)flashPowerDown_addr), ((void *)(flashPowerDown_addr + 0x100)));
    G_SYSCTRL_DeepSleep_flashPowerDown();
}

static uint32_t lightsleep_clkget(void)
{
    uint32_t wakeup_src = MMCU->WKUP_SRC.reg;
    uint32_t lightsleep_clk = 0xffffffff;
    uint32_t wakeupclk_map[32][2] = {
        {(uint32_t)USB_IRQn, (1 << 6) | (1 << 29)},
        {(uint32_t)I2C0_IRQn, (1 << 30)},
        {(uint32_t)I2C1_IRQn, (1 << 30)},
        {(uint32_t)QSPI_IRQn, (1 << 1)},
        {(uint32_t)SPI0_IRQn, (1 << 7)},
        {(uint32_t)SPI1_IRQn, (1 << 7)},
        {(uint32_t)HSPI_IRQn, (1 << 20)},
        {(uint32_t)SEC_IRQn, (1 << 30)},
        {(uint32_t)UART0_IRQn, (1 << 15) | (1 << 29)},
        {(uint32_t)UART1_IRQn, (1 << 15) | (1 << 29)},
        {(uint32_t)UART2_IRQn, (1 << 15) | (1 << 29)},
        {(uint32_t)UART3_IRQn, (1 << 15) | (1 << 29)},
        {(uint32_t)MEMCP_IRQn, (1 << 25)},
        {(uint32_t)SCI0_IRQn, (1 << 12)},
        {(uint32_t)SCI1_IRQn, (1 << 13)},
        {(uint32_t)MSR_IRQn, (1 << 16)},
        {(uint32_t)GPIO_IRQn, (1 << 11)},
        {(uint32_t)TMRG0_IRQn, (1 << 4)},
        {(uint32_t)TMRG1_IRQn, (1 << 4)},
        {(uint32_t)SDIO_IRQn, (1 << 23)},
        {(uint32_t)PSARM_IRQn, (1 << 19)},
        {(uint32_t)RSA_IRQn, (1 << 9)},
        {(uint32_t)SM4_IRQn, (1 << 14)},
        {(uint32_t)TRNG_IRQn, (1 << 0)},
        {(uint32_t)WDT_IRQn, (1 << 5)},
        {(uint32_t)DCMI_IRQn, (1 << 22)},
        {(uint32_t)ADC_IRQn, (1 << 30) | (1 << 29)},
        {(uint32_t)RTC_IRQn, (1 << 30)},
        {(uint32_t)RSVD1_IRQn, (1 << 30)},
        {(uint32_t)POWER_IRQn, (1 << 30)},
        {(uint32_t)SOFTWARE_IRQn, (1 << 30)},
        {(uint32_t)RISCV_IRQn, (1 << 28)},
    };
    for (uint8_t i = 0; i < 32; i++)
    {
        if ((wakeup_src >> i) & 0x01)
        {
            lightsleep_clk &= ~(wakeupclk_map[i][1]);
        }
    }
    lightsleep_clk &= ~((1 << 1));//open qspi clk
    return lightsleep_clk;
}

#ifdef __ICCARM__
/*将函数放入独立section,防止编译优化导致函数体与用到的常量分离*/
#pragma location = "PREFETCH_lightsleep_enter"
#endif
static void lightsleep_enter(uint8_t dvdd, uint32_t d_clk)
{
    uint32_t sysctrl_cl_cls = 0;
    uint16_t ahb_clk_ctrl = 0;
    uint32_t mcu_clk_ctrl = 0;
    uint32_t clkdiv = 0;
    mcu_clk_ctrl = *(volatile uint32_t *)(0xf8410);
    ahb_clk_ctrl = *(volatile uint16_t *)(0xf8414);
    /*cpu clk rc192/16*/
    *(volatile uint32_t *)(0xf8410) = 0x70708;
    __asm("NOP");
    __asm("NOP");
    *(volatile uint32_t *)(0xf8410) = 0x70718;
    __asm("NOP");
    __asm("NOP");
    /*ahb clk mcuclk/2*/
    *(volatile uint16_t *)(0xf8414) = 0x1101;
    sysctrl_cl_cls = MRCC->CLK_EN.reg;
    MRCC->CLK_EN.reg = d_clk;  // 0xffffffff;// close all
    uint8_t u_dvdd = *(volatile uint8_t *)(0xfa801);
    *(volatile uint8_t *)(0xfa801) = (dvdd & 0xf0) == 0 ? (0xb0 | dvdd) : dvdd; // 1v out
    MMCU->CTRL.bit.LTSLEEP_EN = ENABLE;
    MMCU->CTRL.bit.WFI_EN = ENABLE;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN = RESET;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = RESET;
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    MMCU->CTRL.bit.LTSLEEP = ENABLE;
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    MRCC->CLK_EN.reg = sysctrl_cl_cls;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN = SET;
    MLPM->OSC_XTAL.bit.OSC_XTAL_EN_REG = SET;
    *(volatile uint8_t *)(0xfa801) = u_dvdd;
    // wait dvdd up
    for (volatile uint32_t i = 0; i < 500; i++)
    {
        __asm("NOP");
    }
    /*exti light sleep recover clk cfg*/
    *(volatile uint32_t *)(0xf8410) |=  1<<3;
    if((mcu_clk_ctrl & (0x1 << 4))==0) 
    {
        clkdiv = mcu_clk_ctrl ;
        clkdiv |= (0x01 << 4);
        *(volatile uint32_t *)(0xf8410) = clkdiv;
        __asm("NOP");
        __asm("NOP");
        __asm("NOP");
        __asm("NOP");
        __asm("NOP");
        *(volatile uint32_t *)(0xf8410) &= ~(0x01 << 4);
    }
    else
    {
        *(volatile uint32_t *)(0xf8410) = mcu_clk_ctrl;
    }
    *(volatile uint16_t *)(0xf8414) = ahb_clk_ctrl;
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
}
/**
 * @method G_SYSCTRL_Lightleep
 * @brief  cpu enter wfi
 * @param  None
 * @retval None
 */

void G_SYSCTRL_LightSleep(G_SYSCTRL_LightSleepParaDef *Para)
{
    G_LPM_AccessCode(ENABLE);
    G_LPM_RegisterClk(ENABLE);

    /*step 1 close rng*/
    *(volatile uint32_t *)(0xfb260) = 0;
    /*save the current cpu clk*/

    /*step 3 pd & pu unused io*/
    for (uint8_t j = 0; j < 3; j++)
    {
        for (uint8_t i = 0; i < 32; i++)
        {
            if (Para->PD_Unusedio[j] & (1 << i))
            {
                *(volatile uint8_t *)(0xf8700 + j * 32 + i) = PULL_PD;
            }
            if (Para->PU_Unusedio[j] & (1 << i))
            {
                *(volatile uint8_t *)(0xf8700 + j * 32 + i) = PULL_PU;
            }
        }
    }
    /*step 4 lower dvdd*/
    uint32_t primask=__get_PRIMASK();
    __disable_irq();
    uint8_t Addr15E = 0;
    G_OTP_Read(0x15e, &Addr15E, 1);
    uint8_t dvdd = *(volatile uint8_t *)(0xfa801);
    dvdd &= 0x0f;
    dvdd |= ((Addr15E & 0x0f) << 4);
    uint32_t lightsleep_clk_cfg = lightsleep_clkget();
    uint32_t LightStart = (uint32_t)lightsleep_enter;
    ((void (*)(void *, void *))FUNC_PREFETCH)(((void *)LightStart), ((void *)(LightStart + 0x200)));
    /*step 5 enter light sleep*/
    lightsleep_enter(dvdd, lightsleep_clk_cfg);
    /*exti light sleep recover clk cfg*/
    if(primask==0)  __enable_irq();
    NVIC_DisableIRQ(TRNG_IRQn);
    ANA_RNG->RNG_CTRL0.reg |= 0xFFC00000;
    ANA_RNG->RNG_CTRL1.reg = 0x87878787;
    MSYSCTRL->RNG_CTRL = 0;
    delay_ms(5);
    MSYSCTRL->RNG_CTRL = 0x067f;
    delay_ms(5);
    uint32_t couter = 0;
    // rng generation enable
    while ((MSYSCTRL->RNG_CTRL & (1 << 28)) == 0)
    {
        couter++;
        delay_us(10);
        if (couter > 0x1000)
        {
            MSYSCTRL->RNG_CTRL = 0x067f;
        }
    }
}

/**
 * @method G_SYSCTRL_DeepSleepWakeSrcIT
 * @brief  Set light sleep wakeup sources (interrupt wake up)
 * @param  WakeSource : bit0~bit31 corresponding 0~31 irq
 * @param  NewState : ENABLE ：enable wakeup sources
 * @retval None
 */
void G_SYSCTRL_LightSleepWakeSrcIT(uint32_t WakeSource, G_FunctionalState NewState)
{
    if (DISABLE != NewState)
    {
        MMCU->WKUP_SRC.reg |= WakeSource;
    }
    else
    {
        MMCU->WKUP_SRC.reg &= ~WakeSource;
    }
}

/**
 * @method G_SYSCTRL_DeepSleepGpioWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepGpioWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    MLPM->GPIO_WK_LEVEL.reg = WakeSrcPara->Gpio_WakeupLevel;
    MLPM->GPIO_WKEN_W0.reg = WakeSrcPara->Gpio_Pin0_Pin31;
    MLPM->GPIO_WKEN_W1.reg = WakeSrcPara->Gpio_Pin32_Pin63;
    MLPM->GPIO_WKEN_W2.reg = WakeSrcPara->Gpio_Pin64_Pin79;

    G_GPIO_FUN_TYPEDEF fun = WakeSrcPara->Gpio_WakeupLevel == HIGH_WAKEUP ? PULL_PD : PULL_PU;

    for (uint32_t i = 0; i < 32; i++)
    {
        if (WakeSrcPara->Gpio_Pin0_Pin31 & (1 << i))
        {
            GPIO_CONFIG(i) = fun;
        }

        if (WakeSrcPara->Gpio_Pin32_Pin63 & (1 << i))
        {
            GPIO_CONFIG(i + 32) = fun;
        }

        if (WakeSrcPara->Gpio_Pin64_Pin79 & (1 << i))
        {
            GPIO_CONFIG(i + 64) = fun;
        }
    }
}

/**
 * @method G_SYSCTRL_DeepSleepLseRtcWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepLseRtcWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    MLPM->WAKEUP_CTRL.bit.RTC_LSE = ENABLE;
}

/**
 * @method G_SYSCTRL_DeepSleepLsiRtcWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepLsiRtcWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    MLPM->WAKEUP_CTRL.bit.RTC_LSI = ENABLE;
}

/**
 * @method G_SYSCTRL_DeepSleepSecWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepSecWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    MLPM->WAKEUP_CTRL.bit.SEC_EN = ENABLE;
}

/**
 * @method G_SYSCTRL_DeepSleepHChgrWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepHChgrWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    MLPM->CHGR_EVENT_EN.bit.EVENT0 = ENABLE;
    MLPM->CHGR_EVENT_EN.bit.EVENT1 = ENABLE;
    delay_ms(1);
    MLPM->CHGR_WKUP_HI_EN.reg = WakeSrcPara->Chgr_HighWakeEvent;
}

/**
 * @method G_SYSCTRL_DeepSleepLChgrWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepLChgrWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    MLPM->CHGR_EVENT_EN.bit.EVENT0 = ENABLE;
    MLPM->CHGR_EVENT_EN.bit.EVENT1 = ENABLE;
    delay_ms(1);
    MLPM->CHGR_WKUP_LO_EN.reg = WakeSrcPara->Chgr_LowWakeEvent;
}

/**
 * @method G_SYSCTRL_DeepSleepPowerKeyWake
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepPowerKeyWake(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    if (WakeSrcPara->Powkey_WakeLevel)
    {
        MLPM->CHGR_WKUP_LO_EN.bit.PWK = ENABLE;
    }
    else
    {
        MLPM->CHGR_WKUP_HI_EN.bit.PWK = ENABLE;
    }
}

/**
 * @method G_SYSCTRL_DeepSleepWakeDeInit
 * @brief
 * @param  None
 * @retval None
 */
static void G_SYSCTRL_DeepSleepWakeDeInit(void)
{
    MLPM->GPIO_WK_LEVEL.reg = 0;
    MLPM->GPIO_WKEN_W0.reg = 0;
    MLPM->GPIO_WKEN_W1.reg = 0;
    MLPM->GPIO_WKEN_W2.reg = 0;

    MLPM->WAKEUP_CTRL.bit.RTC_LSE = 0;
    MLPM->WAKEUP_CTRL.bit.RTC_LSI = 0;

    MLPM->CHGR_WKUP_HI_EN.bit.PWK = 0;
    MLPM->CHGR_WKUP_LO_EN.bit.PWK = 0;

    MLPM->WAKEUP_CTRL.bit.SEC_EN = 0;

    MLPM->CHGR_EVENT_EN.bit.EVENT0 = 0;
    MLPM->CHGR_EVENT_EN.bit.EVENT1 = 1;
    delay_ms(1);
    MLPM->CHGR_WKUP_LO_EN.reg = 0;
    MLPM->CHGR_WKUP_HI_EN.reg = 0;
}

typedef void (*DeepSleepWakeSrcFunc)(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara);

const DeepSleepWakeSrcFunc DeepSleepWakeSrc[] =
    {
        G_SYSCTRL_DeepSleepGpioWake,
        G_SYSCTRL_DeepSleepLseRtcWake,
        G_SYSCTRL_DeepSleepLsiRtcWake,
        G_SYSCTRL_DeepSleepSecWake,
        G_SYSCTRL_DeepSleepHChgrWake,
        G_SYSCTRL_DeepSleepLChgrWake,
        G_SYSCTRL_DeepSleepPowerKeyWake};
/**
 * @method G_SYSCTRL_DeepSleepWakeSrcIT
 * @brief  Set Deep sleep wakeup sources (interrupt wake up)
 * @param  WakeSrcPara : Reference G_SYSCTRL_DeepSleepWakeSrcParaDef description
 * @retval None
 */
void G_SYSCTRL_DeepSleepWakeSrcIT(G_SYSCTRL_DeepSleepWakeSrcParaDef *WakeSrcPara)
{
    G_LPM_AccessCode(ENABLE);
    G_LPM_RegisterClk(ENABLE);

    G_SYSCTRL_DeepSleepWakeDeInit();

    for (uint8_t i = 0; i < sizeof(DeepSleepWakeSrc) / 4; i++)
    {
        if (WakeSrcPara->SrcType & (1 << i))
        {
            DeepSleepWakeSrc[i](WakeSrcPara);
        }
    }
}

/**
 * @method G_SYSCTRL_SetWakeupRecoverGpio
 * @brief  set wakeup recover gpio function(If the I/O number is small, the configuration is preferred)
 * @param  index: config index,Start from zero and add up(max value is 79)
 * @param  GPIOx: where x can be (GPIOA...GPIOF) to select the GPIO group.
 * @param  GPIO_Pin: select the pin to read.(GPIO_Pin_0...GPIO_Pin_15)(Only one can be configured at a time)
 * @param  type:G_SYSCTRL_LpmRecoverTypeDef
 * @retval TRUE or FALSE
 */
G_Boolean G_SYSCTRL_SetWakeupRecoverGpio(uint8_t index,G_GPIO_TypeDef GPIOx, G_GPIO_Pin_TypeDef GPIO_Pin,G_SYSCTRL_LpmRecoverTypeDef type)
{
    if(index >= 80)
    {
        return FALSE;
    }
    if(SUCCESS != G_BPU_Init())
    {
        return FALSE;
    }
    int gpio_num=GPIO_GetNum(GPIOx, GPIO_Pin);
    if(index==0)
    {
        for(int i=0;i<USER_IO_CFG_LEN;i++)
        {
            ((uint8_t*)&MBPK->KEY)[USER_IO_CFG_SADDR-i] = 0;
        }
        MLPM->BAKEUP_REG3.bit.RECOVER_IO_XOR = 0;
    }
    ((uint8_t*)&MBPK->KEY)[USER_IO_CFG_SADDR-(gpio_num/8)] |= (1<<(gpio_num%8));
    MLPM->BAKEUP_REG3.bit.RECOVER_IO_XOR ^= (1<<(gpio_num%8));
    if((index%4)==0)
    {
        ((uint8_t*)&MBPK->KEY)[USER_IO_FUN_SADDR-(index/4)] = 0;
    }
    ((uint8_t*)&MBPK->KEY)[USER_IO_FUN_SADDR-(index/4)] |= ((type&3)<<((index%4)*2));
    return TRUE;
}

/**
 * @method G_SYSCTRL_SoftReset
 * @brief  Reset
 * @param  None
 * @retval None
 */
void G_SYSCTRL_SoftReset(void)
{
    G_LPM_AccessCode(ENABLE);
    G_LPM_RegisterClk(ENABLE);
    MRSTGEN->RST_EN.bit.SOFT = ENABLE;
    MRSTGEN->RESET.bit.RESET = 0x55;
    while (1)
        ;
}

/**
 * @method G_SYSCTRL_HvldoOcpSel
 * @brief  hvldo overcurrent protection threshold selected
 * @param  None
 * @retval None
 */
void G_SYSCTRL_HvldoOcpSel(G_Boolean Ocp_En)
{
    G_LPM_AccessCode(ENABLE);
    G_LPM_RegisterClk(ENABLE);
    uint8_t Cinfo = 0;
    uint8_t Addr13F = 0;
    G_OTP_Read(0x0a,&Cinfo,1);
    G_OTP_Read(0x13f,&Addr13F,1);
    if(Cinfo == 0x0 && Addr13F == 0x0)
    {
        return;
    }
    if (Ocp_En)
    {
        *(volatile uint8_t *)(0xfa800) |= 0x01;
    }
    else
    {
        *(volatile uint8_t *)(0xfa800) &= ~(0x01);
    }
    return;
}


/**
 * @method G_SYSCTRL_PowerOff
 * @brief  poweroff
 * @param  None
 * @retval None
 */
#ifdef __ICCARM__
/*将函数放入独立section,防止编译优化导致函数体与用到的常量分离*/
#pragma location = "PREFETCH_G_SYSCTRL_PowerOff"
#endif
void G_SYSCTRL_PowerOff(void)
{
    __disable_irq();
    G_LPM_AccessCode(ENABLE);
    G_LPM_RegisterClk(ENABLE);
    uint32_t PowerOffStart = (uint32_t)G_SYSCTRL_PowerOff;
    ((void (*)(void *, void *))FUNC_PREFETCH)(((void *)PowerOffStart), ((void *)(PowerOffStart + 0x200)));
    MLPM->LDO_EXEN_CTRL.bit.GPIO = 0xaa;
    *(volatile uint8_t *)(0xfa810) &= ~(1 << 5); // io fp
    while (1)
    {
        if (ANA_CHGR->STATE.bit.CHGR_IN_DET_AON || MSYSCTRL->pwk_state.reg)
        {
            MRSTGEN->RST_EN.bit.SOFT = ENABLE;
            MRSTGEN->RESET.bit.RESET = 0x55;
        }
        MLPM->PWK_CTRL.bit.LDO_OFF = ENABLE;
    }
}

/************************ (C) COPYRIGHT GKT *****END OF FILE****/
